home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Programmer Disk
/
The Programmer Disk (Microforum).iso
/
xpro
/
c3
/
pro6
/
hrt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-06
|
5KB
|
170 lines
/*Demonstrates the code to use the 8253/8354 timer chip as a
microsecond-resolution general purpose system timer. Also shows
how to disable the Ctrl-C code that DOS uses to abort a program,
which is necessary when we have installed interrupts or otherwise
changed things that must be made right before we exit.
(C) 1991 Bruce Ackerman, Convivia Software.*/
#pragma inline
#include <conio.h>
#include <bios.h>
static void far* oldCint;
/*Installs a simple control-C handler, which ignores the request, thus
disabling Ctrl-C. The installation of this handler will prevent Ctrl-C
or Ctrl-Break from aborting your program, though those silly "^C" things
will still be sent to your screen, and a keystroke may still appear in
the queue, when Ctrl-C is pressed.*/
void ctrlC_install(void)
{
asm mov ax,3523h
asm int 21h /*DOS get vector call*/
asm mov word ptr oldCint,bx
asm mov word ptr oldCint+2,es
asm push ds
asm mov dx,offset intruptC
asm mov ax,cs
asm mov ds,ax
asm mov ax,2523h
asm int 21h /*set int 23 vector*/
asm pop ds
asm jmp short retn
/*Here is the Ctrl-C handler itself*/
asm intruptC:
asm iret
retn: ;
}
void ctrlC_uninstall(void)
{
asm push ds
asm lds dx,oldCint
asm mov ax,2523h
asm int 21h /*DOS reset the vector*/
asm pop ds
}
/*This function is the first one to call before using the 8253 high-resolution
timer. It sets the 8253 channel 0 to use mode 2, which works just as well as
the usual mode 3 for the purpose of generating periodic interrupts (it just
outputs an asymmetric pulse train), but which has the advantage that the
count value only counts down once per tick so we can read it unambiguously.
Because the bios tick count resets at midnight, causing great complexity in
our using it for accurate intervals, we eliminate it altogether and use our
own interrupt handler, which this function installs on int 1C. Therefore
the companion function hrt_close() MUST be called before the program exits!*/
void hrt_open(void)
{
asm mov al,034h
asm out 43h,al /*control reg: mode 2*/
asm xor al,al
asm out 40h,al /*count value 0 (65536)*/
asm out 40h,al
asm mov ax,351Ch
asm int 21h /*DOS get vector call*/
asm mov word ptr cs:oldvect,bx
asm mov word ptr cs:oldvect+2,es
/*install one of our handlers, which one depending on whether the old handler
was just an IRET or if it did anything more. If it was just IRET, we save
time by not chaining back to it*/
asm mov dx,offset intrupt1
asm cmp byte ptr es:[bx],0CFh /*CFh is the IRET opcode*/
asm je use1
asm mov dx,offset intrupt2
use1:
asm push ds
asm mov ax,cs
asm mov ds,ax
asm mov ax,251Ch
asm int 21h /*set int 23 vector*/
asm pop ds
asm jmp short retn
/*Here are the interrupt handlers themselves*/
asm oldvect dd 0 /*storage for the old 1C vector*/
asm tickcnt dw 0 /*the 16-bit tick counter*/
asm intrupt1:
asm inc cs:tickcnt
asm iret /*do our own return*/
asm intrupt2:
asm inc cs:tickcnt
asm jmp dword ptr cs:oldvect /*chain to the old handler*/
retn: ;
}
unsigned long hrt_count; /*the 32-bit time, made public for convenience*/
/*Here is the function which reads our 1.19318 MHz timer, assuming that
we have called hrt_open() beforehand to set it up.*/
unsigned long hrt_read(void)
{
asm mov bx,cs:tickcnt /*get initial tick reading*/
asm mov al,06h
asm out 43h,al /*latch the count value*/
asm in al,40h /*read LS byte*/
asm mov ah,al
asm in al,40h /*read MS byte*/
asm xchg al,ah /*put them where they belong*/
asm not ax
asm inc ax /*convert it so it counts up from 0, not down from 0*/
asm mov cx,cs:tickcnt
asm cmp bx,cx
asm je retn /*if bios counter didn't change, we're done*/
asm cmp ax,8000h /*decide which to use based on whether 8253 count*/
asm jb retn /*was above or below its midpoint*/
asm mov cx,bx
retn:
asm mov word ptr hrt_count,ax
asm mov word ptr hrt_count+2,cx
return hrt_count;
}
/*This function MUST be called before the program exits, after all use of the
high-resolution timer is completed, to uninstall our interrupt handler from
the 1C vector*/
void hrt_close(void)
{
asm mov al,036h
asm out 43h,al /*control reg: mode 3*/
asm xor al,al
asm out 40h,al /*count value 0 (65536)*/
asm out 40h,al
asm push ds
asm lds dx,cs:oldvect
asm test dx,dx /*if dx is 0, ours was never installed*/
asm jz skipit
asm mov ax,251Ch
asm int 21h /*DOS reset the vector*/
skipit: asm pop ds
}
void main()
{
clrscr();
cprintf("\n\n\n\n 1.19318 MHz timer:");
ctrlC_install();
hrt_open(); /*set up the 8253 for our use*/
while (!bioskey(1)) {
gotoxy(9,8);
cprintf("%10lu", hrt_read());
}
hrt_close(); /*put the 8253 back to normal*/
ctrlC_uninstall();
cprintf("\n\n\rFinished...\n");
}